//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Copyright 2012 Microsoft Corporation. All Rights Reserved
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.   
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

namespace Preflight.ServiceModel.Client
{
    using System;
    using System.IO;
    using System.Net;
    using System.Runtime.Serialization.Json;
    using System.Text;
    using Contract;

    using Newtonsoft.Json;

    public class PreflightServiceHttpClient : IPreflightServiceClient
    {
        protected const string HostDetailsResourceName = "host";
        protected const string PreflightCheckResourceName = "check";
        private const string JsonContentType = "application/json";

        public PreflightServiceHttpClient(EndpointDescription endpointDescription)
        {
            this.EndpointDescription = endpointDescription;
        }

        protected EndpointDescription EndpointDescription
        {
            get;
            private set;
        }

        public HostDetails GetHostDetails()
        {
            return this.ExecuteRequest<HostDetails>(HostDetailsResourceName);
        }

        public PreflightCheck RunPreflightCheck()
        {
            return this.ExecuteRequest<PreflightCheck>(PreflightCheckResourceName);
        }

        protected virtual Uri ConstructUri(string resourceName)
        {
            var baseUri = this.EndpointDescription.Properties[CommonPropertyNames.ServiceUri];
            if (baseUri.EndsWith("/") == false)
            {
                baseUri += "/";
            }

            return new Uri(baseUri + "preflight-api/" + resourceName);
        }

        protected virtual void OnBeforeSendingRequest(HttpWebRequest request)
        {
            Log.LogVerbose("OnBeforeSendingRequest was not overriden. No additional actions performed on the request");
        }

        private static HttpWebRequest CreateRequest(Uri uri)
        {
            var request = (HttpWebRequest)WebRequest.Create(uri);
            request.Accept = JsonContentType;
            return request;
        }

        private static TModel Deserialize<TModel>(string response)
        {
            return JsonConvert.DeserializeObject<TModel>(response);
        }

        private TModel ExecuteRequest<TModel>(string resourceName)
        {
            var typeName = typeof(TModel).FullName;
            Log.LogVerbose("Executing request for model: {0}", typeName);
            var uri = this.ConstructUri(resourceName);
            Log.LogVerbose("Uri: {0}", uri);
            var request = CreateRequest(uri);
            Log.LogVerbose("Request built. Sending...");
            var response = this.GetResponse(request);
            Log.LogVerbose("Response: {0}", response);
            return Deserialize<TModel>(response);
        }

        private string GetResponse(HttpWebRequest request)
        {
            this.OnBeforeSendingRequest(request);
            using (var response = (HttpWebResponse)request.GetResponse())
            using (var responseStream = response.GetResponseStream())
            using (var streamReader = new StreamReader(responseStream))
            {
                var responseContent = streamReader.ReadToEnd();
                Log.LogVerbose("Response Content: {0}", responseContent);
                return responseContent;
            }
        }
    }
}
